﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security.Principal;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace blockIP
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            if (!IsAdministrator())
            {
                MessageBox.Show("请以管理员身份运行此程序。", "权限不足", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                Environment.Exit(0); // 退出程序
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string content = textBox1.Text + " | " + textBox2.Text;
            // 提取并去重 IP 地址
            HashSet<string> uniqueIPs = ExtractIPs(content);

            // 显示提取的 IP 地址数量，并确认是否添加到防火墙
            var result = MessageBox.Show($"提取到 {uniqueIPs.Count} 个 IP 地址。是否将这些IP加入防火墙入站规则进行屏蔽？", "确认", MessageBoxButtons.YesNo);
            if (result == DialogResult.Yes)
            {
                try
                {
                    AddOrUpdateIPsToFirewall(uniqueIPs);
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"插入失败，请使用管理员身份再试一次！\n错误信息: {ex.Message}");
                }
            }
        }

        private HashSet<string> ExtractIPs(string content)
        {
            string ipPattern = @"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b";
            Regex regex = new Regex(ipPattern);
            MatchCollection matches = regex.Matches(content);

            HashSet<string> uniqueIPs = new HashSet<string>();

            foreach (Match match in matches)
            {
                uniqueIPs.Add(match.Value);
            }

            return uniqueIPs;
        }

        private void AddOrUpdateIPsToFirewall(HashSet<string> ips)
        {
            string ruleName = "Blocked IPs";
            string ipList = string.Join(",", ips);
            string checkRuleArguments = $"advfirewall firewall show rule name=\"{ruleName}\"";

            string checkOutput = ExecuteNetshCommand(checkRuleArguments);
            
            if (checkOutput.Contains("No rules match") || checkOutput.Contains("没有与指定标准相匹配的规则"))
            {
                // If the rule does not exist, create it
                string addArguments = $"advfirewall firewall add rule name=\"{ruleName}\" dir=in action=block protocol=any remoteip={ipList}";
                ExecuteNetshCommand(addArguments);
                MessageBox.Show("已经将所有IP插入到防火墙入站规则！");
            }
            else
            {
                // If the rule exists, update it
                string updateArguments = $"advfirewall firewall set rule name=\"{ruleName}\" new remoteip={ipList}";
                ExecuteNetshCommand(updateArguments);
                MessageBox.Show("防火墙入站规则已更新！");
            }
            string remoteIPs = string.Join("\r\n", GetRemoteIPsForRule("Blocked IPs"));
            textBox2.Text = remoteIPs;
            textBox1.Clear();
        }

        private string ExecuteNetshCommand(string arguments)
        {
            ProcessStartInfo psi = new ProcessStartInfo("netsh", arguments)
            {
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true
            };

            using (Process process = Process.Start(psi))
            {
                // 使用异步读取输出和错误流，避免死锁
                string output = string.Empty;
                string error = string.Empty;
                process.OutputDataReceived += (sender, e) => { if (e.Data != null) output += e.Data + Environment.NewLine; };
                process.ErrorDataReceived += (sender, e) => { if (e.Data != null) error += e.Data + Environment.NewLine; };

                process.BeginOutputReadLine();
                process.BeginErrorReadLine();

                process.WaitForExit();
                                
                return output;
            }
        }

        private bool IsAdministrator()
        {
            using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
            {
                WindowsPrincipal principal = new WindowsPrincipal(identity);
                return principal.IsInRole(WindowsBuiltInRole.Administrator);
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            string remoteIPs = string.Join("\r\n", GetRemoteIPsForRule("Blocked IPs"));
            textBox2.Text = remoteIPs;
        }

        private List<string> GetRemoteIPsForRule(string ruleName)
        {
            List<string> remoteIPs = new List<string>();

            try
            {
                Process process = new Process();
                process.StartInfo.FileName = "netsh";
                process.StartInfo.Arguments = $"advfirewall firewall show rule name=\"{ruleName}\"";
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.CreateNoWindow = true;
                process.Start();

                string output = process.StandardOutput.ReadToEnd();
                process.WaitForExit();

                string pattern = @"远程 IP:\s*(.+)";
                MatchCollection matches = Regex.Matches(output, pattern, RegexOptions.IgnoreCase);

                foreach (Match match in matches)
                {
                    if (match.Groups.Count > 1)
                    {
                        string ips = match.Groups[1].Value.Trim();
                        string ipPattern = @"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})";
                        MatchCollection ipMatches = Regex.Matches(ips, ipPattern);

                        foreach (Match ipMatch in ipMatches)
                        {
                            remoteIPs.Add(ipMatch.Value);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error reading remote IPs: " + ex.Message);
            }

            return remoteIPs;
        }
    }
}
